<!--
@license
Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<link rel="import" href="../paper-slider/paper-slider.html">
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../tf-backend/tf-backend.html">
<link rel="import" href="../tf-card-heading/tf-card-heading.html">
<link rel="import" href="../tf-card-heading/tf-card-heading-style.html">
<link rel="import" href="../tf-card-heading/util.html">
<link rel="import" href="../tf-color-scale/tf-color-scale.html">
<link rel="import" href="../tf-dashboard-common/tensorboard-color.html">
<link rel="import" href="../tf-imports/d3.html">
<link rel="import" href="../tf-imports/lodash.html">
<link rel="import" href="../tf-markdown-view/tf-markdown-view.html">

<!--
tf-audio-loader loads an individual audio clip from the TensorBoard
backend.
-->
<dom-module id="tf-audio-loader">
  <template>
    <tf-card-heading
      tag="[[tag]]"
      run="[[run]]"
      display-name="[[tagMetadata.displayName]]"
      description="[[tagMetadata.description]]"
      color="[[_runColor]]"
    >
      <template is="dom-if" if="[[_hasMultipleSamples]]">
        <div class="heading-row">
          <div class="heading-label">
            sample: [[_sampleText]] of [[totalSamples]]
          </div>
        </div>
      </template>
      <template is="dom-if" if="[[_hasAtLeastOneStep]]">
        <div class="heading-row">
          <div class="heading-label">
            step <strong>[[_currentDatum.step]]</strong>
          </div>
          <template is="dom-if" if="[[_currentDatum.wall_time]]">
            <div class="heading-label heading-right">
              [[_currentDatum.wall_time]]
            </div>
          </template>
        </div>
      </template>
      <template is="dom-if" if="[[_hasMultipleSteps]]">
        <div class="heading-row">
          <paper-slider
              id="steps"
              immediate-value="{{_stepIndex}}"
              max="[[_maxStepIndex]]"
              max-markers="[[_maxStepIndex]]"
              snaps
              step="1"
              value="{{_stepIndex}}"
          ></paper-slider>
        </div>
      </template>
    </tf-card-heading>
    <template is="dom-if" if="[[_hasAtLeastOneStep]]">
      <audio
        controls
        loop="loop"
        src$="[[_currentDatum.url]]"
        type$="[[_currentDatum.contentType]]"
      ></audio>
      <tf-markdown-view html="[[_currentDatum.label]]"></tf-markdown-view>
    </template>
    <div id="main-audio-container">
    </div>

    <style include="tf-card-heading-style">
      :host {
        display: block;
        width: 350px;
        height: auto;
        position: relative;
        --step-slider-knob-color: #424242;
        margin-right: 15px;
        margin-bottom: 15px;
      }

      #steps {
        height: 15px;
        margin: 0 0 0 -15px;
        width: 100%;
        box-sizing: border-box;
        padding: 0 5px;  /* so the slider knob doesn't butt out */
        margin-top: 5px;
        --paper-slider-active-color: var(--step-slider-knob-color);
        --paper-slider-knob-color: var(--step-slider-knob-color);
        --paper-slider-pin-color: var(--step-slider-knob-color);
        --paper-slider-knob-start-color: var(--step-slider-knob-color);
        --paper-slider-knob-start-border-color: var(--step-slider-knob-color);
        --paper-slider-pin-start-color: var(--step-slider-knob-color);
      }
    </style>
  </template>
  <script>
    "use strict";

    Polymer({
      is: "tf-audio-loader",
      properties: {
        run: String,
        tag: String,
        sample: Number,
        totalSamples: Number,  // how many samples in this run--tag combination?
        /** @type {{description: string, displayName: string}} */
        tagMetadata: Object,

        _runColor: {
          type: String,
          computed: '_computeRunColor(run)',
        },

        requestManager: Object,
        _metadataCanceller: {
          type: Object,
          value: () => new tf_backend.Canceller(),
        },

        // _steps: {
        //   wall_time: string,
        //   step: number,
        //   label: string,
        //   contentType: string,
        //   url: string,
        // }[]
        _steps: {
          type: Array,
          value: () => [],
        },
        _stepIndex: Number,
        _hasAtLeastOneStep: {
          type: Boolean,
          computed: "_computeHasAtLeastOneStep(_steps)",
        },
        _hasMultipleSteps: {
          type: Boolean,
          computed: "_computeHasMultipleSteps(_steps)",
        },
        _currentDatum: {
          type: Object,  // {wall_time, step, label, url}
          computed: "_computeCurrentDatum(_steps, _stepIndex)",
        },
        _maxStepIndex: {
          type: Number,
          computed: "_computeMaxStepIndex(_steps)",
        },
        _sampleText: {
          type: String,
          computed: "_computeSampleText(sample)",
        },
        _hasMultipleSamples: {
          type: Boolean,
          computed: "_computeHasMultipleSamples(totalSamples)",
        },
      },
      observers: ['reload(run, tag)'],
      _computeRunColor(run) {
        return tf_color_scale.runsColorScale(run);
      },
      _computeHasAtLeastOneStep(steps) {
        return !!steps && steps.length > 0;
      },
      _computeHasMultipleSteps(steps) {
        return !!steps && steps.length > 1;
      },
      _computeMaxStepIndex(steps) {
        return steps.length - 1;
      },
      _computeCurrentDatum(steps, stepIndex) {
        return steps[stepIndex];
      },
      _computeSampleText(sample) {
        return `${sample + 1}`;
      },
      _computeHasMultipleSamples(totalSamples) {
        return totalSamples > 1;
      },

      attached() {
        this._attached = true;
        this.reload();
      },
      reload() {
        if (!this._attached) {
          return;
        }
        this._metadataCanceller.cancelAll();
        const router = tf_backend.getRouter();
        const url = tf_backend.addParams(router.pluginRoute('audio', '/audio'), {
            tag: this.tag,
            run: this.run,
            sample: this.sample,
        });
        const updateSteps = this._metadataCanceller.cancellable(result => {
          if (result.cancelled) {
            return;
          }
          const data = result.value;
          const steps = data.map(this._createStepDatum.bind(this));
          this.set("_steps", steps);
          this.set("_stepIndex", steps.length - 1);
        });
        this.requestManager.request(url).then(updateSteps);
      },
      _createStepDatum(audioMetadata) {
        let url = tf_backend.getRouter().pluginRoute('audio', '/individualAudio');
        // Include wall_time just to disambiguate the URL and force
        // the browser to reload the audio when the URL changes. The
        // backend doesn't care about the value.
        url = tf_backend.addParams(url, {ts: audioMetadata.wall_time});
        url += '&' + audioMetadata.query;

        return {
          wall_time: tf_card_heading.formatDate(new Date(audioMetadata.wall_time * 1000)),
          step: audioMetadata.step,
          label: audioMetadata.label,
          contentType: audioMetadata.contentType,
          url,
        };
      },
    });
  </script>
</dom-module>
